package com.clt.web.common;

import java.io.IOException;
import java.util.Iterator;
import java.util.Map;
import java.util.Map.Entry;
import java.util.Set;
import java.util.SortedMap;
import java.util.TreeMap;
import java.util.concurrent.ExecutionException;

import javax.servlet.http.HttpServletRequest;

import org.apache.commons.lang.StringUtils;
import org.dom4j.DocumentException;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import com.clt.web.service.IWeixinKitService;
import com.clt.web.utils.MD5Util;
import com.clt.web.utils.ParseXmlUtil;

/**
 * 
 * 支付生成prepay_id
 * 
 * @author Zhou Yingying
 * 
 */

public class Pay {
	
	private static final Logger LOG = LoggerFactory.getLogger(Pay.class);
	private static final String UNIFIEDORDER_URL= "https://api.mch.weixin.qq.com/pay/unifiedorder";// 统一下单接口
	

    /**
     * 微信支付V3
     * 统一下单接口
     * @param req
     * @param totalFee 商品价格
     * @param body 商品描述
     * @param openId 账号openid
     * @param orderNo 订单Id
     * @param nonce_str 随机字符串
     * @param notify_url 回调URL
     * @param trade_type JSAPI(公众号调用)、 NATIVE、 APP
     * @param productId trade_type 为 NATIVE时需要填写
     * @return
     * @throws IOException
     * @throws ExecutionException
     * @throws InterruptedException
     * @throws DocumentException
     */
    public static String unifiedorder(HttpServletRequest req,String totalFee, String body, String openId, String orderNo, String nonce_str,
    		 String notify_url, String trade_type, String productId) 
    				throws IOException, ExecutionException, InterruptedException, DocumentException{
		// 订单生成的机器 IP
    	IWeixinKitService weixinKit = WeixinKitFactory.getWeixinKit();
		String spbill_create_ip = getIp(req);
		// 这里notify_url是 支付完成后微信发给该链接信息，可以判断会员是否支付成功，改变订单状态等。
		SortedMap<String, String> packageParams = new TreeMap<String, String>();
		packageParams.put("appid", weixinKit.getAppid());
		packageParams.put("mch_id", weixinKit.getMchId());
		packageParams.put("nonce_str", nonce_str);
		packageParams.put("body", body);
		packageParams.put("out_trade_no", orderNo);
		packageParams.put("total_fee", totalFee); // 商品金额
		packageParams.put("spbill_create_ip", spbill_create_ip);
		packageParams.put("notify_url", notify_url);
		packageParams.put("trade_type", trade_type);
		if(StringUtils.isNotBlank(openId)){
			packageParams.put("openid", openId);
		}
		if(StringUtils.isNotBlank(productId)){
			packageParams.put("product_id", productId);
		}

		String sign = Pay.createSign(packageParams);
		
		// 构造POST参数
		StringBuffer xml = new StringBuffer("<xml>" 
				+ "<appid>" + weixinKit.getAppid() + "</appid>" 
				+ "<mch_id>" + weixinKit.getMchId() + "</mch_id>" 
				+ "<nonce_str>" + nonce_str+ "</nonce_str>" 
				+ "<sign><![CDATA[" + sign + "]]></sign>"
				+ "<body><![CDATA[" + body + "]]></body>"
				+ "<out_trade_no>"+ orderNo+ "</out_trade_no>"
				+ "<total_fee>"+ totalFee + "</total_fee>"
				+ "<spbill_create_ip>" + spbill_create_ip + "</spbill_create_ip>"
				+ "<notify_url>" + notify_url + "</notify_url>"
				+ "<trade_type>" + trade_type + "</trade_type>" );
		if(StringUtils.isNotBlank(openId)){
			xml.append("<openid>"+ openId + "</openid>");
		}
		if(StringUtils.isNotBlank(productId)){
			xml.append("<product_id>"+ productId + "</product_id>");
		}
    	xml.append("</xml>");
    
    	//XML转utf-8
    	String prePayXml = new String(xml.toString().getBytes(), "UTF-8");
		String resultFromWeixin = HttpKit.post(UNIFIEDORDER_URL, prePayXml.toString());
		Map<String,String> resultMap =  ParseXmlUtil.parseXml(resultFromWeixin);
		String prepay_id =  resultMap.get("prepay_id");
		if (prepay_id==null || prepay_id.equals("")) {
			LOG.error("微信统一支付下单接口 (unifiedorder) 错误, cause by {} and {}", new Object[]{resultMap.get("return_msg"), resultMap});
		} else {
			LOG.info("微信统一支付下单接口 (unifiedorder) prepay_id is {}", prepay_id);
		}
		return prepay_id;
    }
	
    /**
     * 微信支付V3 签名
	 * 创建md5摘要,规则是:按参数名称a-z排序,遇到空值的参数不参加签名。
	 */
	public static String createSign(SortedMap<String, String> packageParams) {
		IWeixinKitService weixinKit = WeixinKitFactory.getWeixinKit();
		StringBuffer sb = new StringBuffer();
		Set<Entry<String, String>> es = packageParams.entrySet();
		Iterator<Entry<String, String>> it = es.iterator();
		while (it.hasNext()) {
			Entry<String, String> entry = it.next();
			String k = entry.getKey();
			String v = entry.getValue();
			if (null != v && !"".equals(v) && !"sign".equals(k)
					&& !"key".equals(k)) {
				sb.append(k + "=" + v + "&");
			}
		}
		sb.append("key=" + weixinKit.getPartnerkey());
		String sign = MD5Util.MD5Encode(sb.toString(), "UTF-8")
				.toUpperCase();
		return sign;
	}

	
	/**
	* 获取ip地址
	* @param request
	* @return
	*/
	public static String getIp(HttpServletRequest request) {
		if (request == null)
			return "";
		String ip = request.getHeader("X-Requested-For");
		if (StringUtils.isEmpty(ip) || "unknown".equalsIgnoreCase(ip)) {
			ip = request.getHeader("X-Forwarded-For");
		}
		if (StringUtils.isEmpty(ip) || "unknown".equalsIgnoreCase(ip)) {
			ip = request.getHeader("Proxy-Client-IP");
		}
		if (StringUtils.isEmpty(ip) || "unknown".equalsIgnoreCase(ip)) {
			ip = request.getHeader("WL-Proxy-Client-IP");
		}
		if (StringUtils.isEmpty(ip) || "unknown".equalsIgnoreCase(ip)) {
			ip = request.getHeader("HTTP_CLIENT_IP");
		}
		if (StringUtils.isEmpty(ip) || "unknown".equalsIgnoreCase(ip)) {
			ip = request.getHeader("HTTP_X_FORWARDED_FOR");
		}
		if (StringUtils.isEmpty(ip) || "unknown".equalsIgnoreCase(ip)) {
			ip = request.getRemoteAddr();
		}
		return ip;
	}

	/** 
     * 把中文转成Unicode码 
     * 
     * 防止body中文乱码问题
     * @param str 
     * @return 
     */ 
    public static String chinaToUnicode(String str){  
        String result="";  
        for (int i = 0; i < str.length(); i++){  
            int chr1 = (char) str.charAt(i);  
            if(chr1>=19968&&chr1<=171941){//汉字范围 \u4e00-\u9fa5 (中文)  
                result+="\\u" + Integer.toHexString(chr1);  
            }else{  
                result+=str.charAt(i);  
            }  
        }  
        return result;  
    }
}

